from basicNode import basicNode
from basicEdge import basicEdge
from basicRoute import basicRoute
import time
import car
import route

class graphoid:

    def __init__(self, fileWithDataName=None):
        self.listOfNodes = []
        self.listOfEdges = []
        self.listOfRoutes = []
        if fileWithDataName != None:
            fileWithData = open(fileWithDataName)
            lines = fileWithData.readlines()
            self.deltaT = float(lines[0].split(" ")[0])
            del lines[0]
            
            numberOfNodes = int( lines[0].split(" ")[0] )
            numberOfEdges = int( lines[1].split(" ")[0] )
            numberOfRoutes = int( lines[2].split(" ")[0] )
            numberOfCars = int( lines[3].split(" ")[0] )
            
            lines = lines[4:]
            rawListOfNodes = lines[:numberOfNodes]
            rawListOfEdges = lines[numberOfNodes:numberOfNodes+numberOfEdges]
            rawListOfRoutes = lines[numberOfNodes+numberOfEdges:numberOfNodes + numberOfEdges + numberOfRoutes]
            rawListOfCars = lines[numberOfNodes + numberOfEdges + numberOfRoutes:]        
            
            tableOfNodes = {}
            edges = []
            
            number = 0
            
            for line in rawListOfNodes:
                nodeCoordinates = line.split(" ")
                x = float( nodeCoordinates[0] )
                y = float( nodeCoordinates[1] )
                hasLights = int( nodeCoordinates[2] ) == 1
                tableOfNodes[number] = basicNode(x, y, number, True, hasLights)
                number = number + 1
                
            dictForEdges = {}
            counter = 0
            
            for line in rawListOfEdges:
                nodes = line.split(" ")
                numberOfStartNode = int( nodes[0] )
                numberOfEndNode =   int( nodes[1] )
                e =  basicEdge(tableOfNodes[numberOfStartNode], tableOfNodes[numberOfEndNode], counter) 
                counter += 1
                edges += [e]
                dictForEdges[ (numberOfStartNode,numberOfEndNode) ] = e
                
            for elem in tableOfNodes:
                self.listOfNodes += [tableOfNodes[elem]]
                
            for elem in edges:
                self.listOfEdges += [elem]

            counter = 0         
            for line in rawListOfRoutes:
                nodes = line.split(" ")
                r = route.route(counter)
                counter += 1
                for i in range(len(nodes) - 1):
                    numberOfStartNode = int( nodes[i] )
                    numberOfEndNode =   int( nodes[i+1] )
                    r.addEdge( dictForEdges[numberOfStartNode, numberOfEndNode] )
                self.listOfRoutes += [r]
                    
            counter = 0     
            for line in rawListOfCars:
                data = line.split(" ")
                position = int(data[0])    
                speed = float(data[1])
                r = self.listOfRoutes[ int(data[2]) ]
                e = r.get(0)
                acc = float(data[3])
                self.listOfCars += [car.car(e,position,speed,r,counter,acc)]
                counter += 1


    def addNode(self, x, y, safe=False):
        #TODO: pewnie jeszcze cos sie robi poza wsadzeniem na koniec listy?
        self.listOfNodes.append(basicNode(x, y, None, safe)) #nie uzywam na razie ID (=None)
        return self.listOfNodes[-1]

    def addEdge(self, startNode, endNode):
        #TODO: j.w.
        self.listOfEdges.append(basicEdge(startNode, endNode, None)) #nie uzywam na razie ID (=None)
        return self.listOfEdges[-1]

    def addRoute(self, ID=None):
        self.listOfRoutes.append(basicRoute(ID))
        return self.listOfRoutes[-1]

    def getNodes(self):
        return self.listOfNodes

    def getEdges(self):
        return self.listOfEdges
    
    def getRoutes(self):
        return self.listOfRoutes
    
    def getAdjacentEdges(self, basicNode):
        return filter(lambda e: basicNode in [e.startNode, e.endNode], self.listOfEdges)
        
    def getAdjacentRoutes(self, basicEdge):
        return filter(lambda r: r.hasEdge(basicEdge), self.listOfRoutes)    
        
    def delNode(self, basicNode):
        adj = self.getAdjacentEdges(basicNode)
        assert adj == []
        for a in adj:
            self.delEdge(a)
        self.listOfNodes.remove(basicNode)
        
    def delEdge(self, basicEdge):
        adj = self.getAdjacentRoutes(basicEdge)
        assert adj == []
        for a in adj:
            self.delRoute(a)
        self.listOfEdges.remove(basicEdge)
    
    def delRoute(self, route):
        self.listOfRoutes.remove(route)
        
    def shortestPath(self, startNode, endNode):
        Q = [startNode]
        V = dict([(n, 0) for n in self.getNodes()])
        P = dict([(n, None) for n in self.getNodes()])
        while (Q):
            act = Q[0]
            Q = Q[1:]
            if act == endNode:
                res = []
                while act != startNode:
                    res.insert(0, P[act])
                    act = P[act].startNode
                return res
                
            for e in self.getEdges():
                if e.startNode == act and V[e.endNode] == 0:
                    Q.append(e.endNode)
                    V[e.endNode] = 1
                    P[e.endNode] = e
        return None
        
    def findIntersections(self, sx, sy, ex, ey):
        res = []
        for e in self.getEdges():
            alpha = e.findIntersection(sx, sy, ex, ey)       
            if alpha != None:
                res.append((alpha, e))
        res.sort()
        return res
    def findNode(self, x, y):
        nodes = self.getNodes()
        for n in nodes:
            if n.isInNode(x, y):
                return n
        return None
    def findEdge(self, x, y):
        edges = self.getEdges()
        for e in edges:
            if e.isInEdge(x, y):
                return e
        return None
